<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>03-05数据库学习 | 个人博客</title><meta name="keywords" content="MySQL"><meta name="author" content="蔡哞哞"><meta name="copyright" content="蔡哞哞"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta http-equiv="Cache-Control" content="no-transform"><meta http-equiv="Cache-Control" content="no-siteapp"><meta name="description" content="Datetime和Timestamp、隔离级别、B 树B+树Hash索引、数据库连接池相关、索引类型、MySQL基础架构分析、数据类型(列类型)、表的操作、列约束、select、建表规范">
<meta property="og:type" content="article">
<meta property="og:title" content="03-05数据库学习">
<meta property="og:url" content="https://caixm1025.gitee.io/2021/03/06/03-05%E6%95%B0%E6%8D%AE%E5%BA%93%E5%AD%A6%E4%B9%A0/index.html">
<meta property="og:site_name" content="个人博客">
<meta property="og:description" content="Datetime和Timestamp、隔离级别、B 树B+树Hash索引、数据库连接池相关、索引类型、MySQL基础架构分析、数据类型(列类型)、表的操作、列约束、select、建表规范">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://caixm1025.gitee.io/img/%E5%9B%BE%E7%89%875.jpg">
<meta property="article:published_time" content="2021-03-06T10:47:31.000Z">
<meta property="article:modified_time" content="2021-03-06T10:52:56.493Z">
<meta property="article:author" content="蔡哞哞">
<meta property="article:tag" content="MySQL">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://caixm1025.gitee.io/img/%E5%9B%BE%E7%89%875.jpg"><link rel="shortcut icon" href="/everyday/img/25.png"><link rel="canonical" href="https://caixm1025.gitee.io/2021/03/06/03-05%E6%95%B0%E6%8D%AE%E5%BA%93%E5%AD%A6%E4%B9%A0/"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/everyday/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><script>var GLOBAL_CONFIG = { 
  root: '/everyday/',
  algolia: undefined,
  localSearch: undefined,
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    jQuery: 'https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js',
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/js/jquery.justifiedGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/css/justifiedGallery.min.css'
    },
    fancybox: {
      js: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js',
      css: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isanchor: false
};

var saveToLocal = {
  set: function setWithExpiry(key, value, ttl) {
    const now = new Date()
    const expiryDay = ttl * 86400000
    const item = {
      value: value,
      expiry: now.getTime() + expiryDay,
    }
    localStorage.setItem(key, JSON.stringify(item))
  },

  get: function getWithExpiry(key) {
    const itemStr = localStorage.getItem(key)

    if (!itemStr) {
      return undefined
    }
    const item = JSON.parse(itemStr)
    const now = new Date()

    if (now.getTime() > item.expiry) {
      localStorage.removeItem(key)
      return undefined
    }
    return item.value
  }
}

// https://stackoverflow.com/questions/16839698/jquery-getscript-alternative-in-native-javascript
const getScript = url => new Promise((resolve, reject) => {
  const script = document.createElement('script')
  script.src = url
  script.async = true
  script.onerror = reject
  script.onload = script.onreadystatechange = function() {
    const loadState = this.readyState
    if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
    script.onload = script.onreadystatechange = null
    resolve()
  }
  document.head.appendChild(script)
})</script><script id="config_change">var GLOBAL_CONFIG_SITE = { 
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2021-03-06 18:52:56'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(function () {  window.activateDarkMode = function () {
    document.documentElement.setAttribute('data-theme', 'dark')
    if (document.querySelector('meta[name="theme-color"]') !== null) {
      document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
    }
  }
  window.activateLightMode = function () {
    document.documentElement.setAttribute('data-theme', 'light')
   if (document.querySelector('meta[name="theme-color"]') !== null) {
      document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
    }
  }
  const autoChangeMode = 'false'
  const t = saveToLocal.get('theme')
  if (autoChangeMode === '1') {
    const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches
    const isLightMode = window.matchMedia('(prefers-color-scheme: light)').matches
    const isNotSpecified = window.matchMedia('(prefers-color-scheme: no-preference)').matches
    const hasNoSupport = !isDarkMode && !isLightMode && !isNotSpecified
    if (t === undefined) {
      if (isLightMode) activateLightMode()
      else if (isDarkMode) activateDarkMode()
      else if (isNotSpecified || hasNoSupport) {
        const now = new Date()
        const hour = now.getHours()
        const isNight = hour <= 6 || hour >= 18
        isNight ? activateDarkMode() : activateLightMode()
      }
      window.matchMedia('(prefers-color-scheme: dark)').addListener(function (e) {
        if (saveToLocal.get('theme') === undefined) {
          e.matches ? activateDarkMode() : activateLightMode()
        }
      })
    } else if (t === 'light') activateLightMode()
    else activateDarkMode()
  } else if (autoChangeMode === '2') {
    const now = new Date()
    const hour = now.getHours()
    const isNight = hour <= 6 || hour >= 18
    if (t === undefined) isNight ? activateDarkMode() : activateLightMode()
    else if (t === 'light') activateLightMode()
    else activateDarkMode()
  } else {
    if (t === 'dark') activateDarkMode()
    else if (t === 'light') activateLightMode()
  }const asideStatus = saveToLocal.get('aside-status')
if (asideStatus !== undefined) {
   if (asideStatus === 'hide') {
     document.documentElement.classList.add('hide-aside')
   } else {
     document.documentElement.classList.remove('hide-aside')
   }
}})()</script><meta name="generator" content="Hexo 5.3.0"><link rel="alternate" href="/everyday/atom.xml" title="个人博客" type="application/atom+xml">
</head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="author-avatar"><img class="avatar-img" src="/everyday/img/image011.png" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data"><div class="data-item is-center"><div class="data-item-link"><a href="/everyday/archives/"><div class="headline">文章</div><div class="length-num">28</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/everyday/tags/"><div class="headline">标签</div><div class="length-num">19</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/everyday/categories/"><div class="headline">分类</div><div class="length-num">4</div></a></div></div></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/everyday/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/everyday/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/everyday/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/everyday/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 列表</span><i class="fas fa-chevron-down expand"></i></a><ul class="menus_item_child"><li><a class="site-page" href="/everyday/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li><li><a class="site-page" href="/everyday/movies/"><i class="fa-fw fas fa-video"></i><span> 电影</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/everyday/link/"><i class="fa-fw fas fa-link"></i><span> 友情链接</span></a></div><div class="menus_item"><a class="site-page" href="/everyday/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url(/everyday/img/%E5%9B%BE%E7%89%875.jpg)"><nav id="nav"><span id="blog_name"><a id="site-name" href="/everyday/">个人博客</a></span><div id="menus"><div class="menus_items"><div class="menus_item"><a class="site-page" href="/everyday/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/everyday/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/everyday/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/everyday/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 列表</span><i class="fas fa-chevron-down expand"></i></a><ul class="menus_item_child"><li><a class="site-page" href="/everyday/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li><li><a class="site-page" href="/everyday/movies/"><i class="fa-fw fas fa-video"></i><span> 电影</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/everyday/link/"><i class="fa-fw fas fa-link"></i><span> 友情链接</span></a></div><div class="menus_item"><a class="site-page" href="/everyday/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">03-05数据库学习</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2021-03-06T10:47:31.000Z" title="发表于 2021-03-06 18:47:31">2021-03-06</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2021-03-06T10:52:56.493Z" title="更新于 2021-03-06 18:52:56">2021-03-06</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/everyday/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/">数据库</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-pv-cv"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="全文绝大部分内容来自：https-gitee-com-SnailClimb-JavaGuide"><a href="#全文绝大部分内容来自：https-gitee-com-SnailClimb-JavaGuide" class="headerlink" title="全文绝大部分内容来自：https://gitee.com/SnailClimb/JavaGuide"></a>全文绝大部分内容来自：<a target="_blank" rel="noopener" href="https://gitee.com/SnailClimb/JavaGuide">https://gitee.com/SnailClimb/JavaGuide</a></h1><h2 id="1、Datetime-和-Timestamp"><a href="#1、Datetime-和-Timestamp" class="headerlink" title="1、Datetime 和 Timestamp"></a>1、Datetime 和 Timestamp</h2><p><strong>通常我们都会首选 Timestamp。</strong> </p>
<p><strong>DateTime 类型是没有时区信息的（时区无关）</strong> ，DateTime 类型保存的时间都是当前会话所设置的时区对应的时间。这样就会有什么问题呢？当你的时区更换之后，比如你的服务器更换地址或者更换客户端连接时区设置的话，就会导致你从数据库中读出的时间错误。不要小看这个问题，很多系统就是因为这个问题闹出了很多笑话。</p>
<p><strong>Timestamp 和时区有关</strong>。Timestamp 类型字段的值会随着服务器时区的变化而变化，自动换算成相应的时间，说简单点就是在不同时区，查询到同一个条记录此字段的值会不一样。</p>
<p>举例：</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> `time_zone_test` (</span><br><span class="line">  `id` <span class="type">bigint</span>(<span class="number">20</span>) <span class="keyword">NOT</span> <span class="keyword">NULL</span> AUTO_INCREMENT,</span><br><span class="line">  `date_time` datetime <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span>,</span><br><span class="line">  `time_stamp` <span class="type">timestamp</span> <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="built_in">CURRENT_TIMESTAMP</span> <span class="keyword">ON</span> <span class="keyword">UPDATE</span> <span class="built_in">CURRENT_TIMESTAMP</span>,</span><br><span class="line">  <span class="keyword">PRIMARY</span> <span class="keyword">KEY</span> (`id`)</span><br><span class="line">) ENGINE<span class="operator">=</span>InnoDB <span class="keyword">DEFAULT</span> CHARSET<span class="operator">=</span>utf8;</span><br></pre></td></tr></table></figure>
<p>插入数据：</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> time_zone_test(date_time,time_stamp) <span class="keyword">VALUES</span>(NOW(),NOW());</span><br></pre></td></tr></table></figure>
<p>查看数据：</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> date_time,time_stamp <span class="keyword">from</span> time_zone_test;</span><br></pre></td></tr></table></figure>
<p>结果：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">+---------------------+---------------------+</span><br><span class="line">| date_time           | time_stamp          |</span><br><span class="line">+---------------------+---------------------+</span><br><span class="line">| 2020-01-11 09:53:32 | 2020-01-11 09:53:32 |</span><br><span class="line">+---------------------+---------------------+</span><br></pre></td></tr></table></figure>
<p>现在我们运行</p>
<p>修改当前会话的时区:</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">set</span> time_zone<span class="operator">=</span><span class="string">&#x27;+8:00&#x27;</span>;</span><br></pre></td></tr></table></figure>
<p>再次查看数据：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">+---------------------+---------------------+</span><br><span class="line">| date_time           | time_stamp          |</span><br><span class="line">+---------------------+---------------------+</span><br><span class="line">| 2020-01-11 09:53:32 | 2020-01-11 17:53:32 |</span><br><span class="line">+---------------------+---------------------+</span><br></pre></td></tr></table></figure>
<p><strong>扩展：一些关于 MySQL 时区设置的一个常用 sql 命令</strong></p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"># 查看当前会话时区</span><br><span class="line"><span class="keyword">SELECT</span> @<span class="variable">@session</span>.time_zone;</span><br><span class="line"># 设置当前会话时区</span><br><span class="line"><span class="keyword">SET</span> time_zone <span class="operator">=</span> <span class="string">&#x27;Europe/Helsinki&#x27;</span>;</span><br><span class="line"><span class="keyword">SET</span> time_zone <span class="operator">=</span> &quot;+00:00&quot;;</span><br><span class="line"># 数据库全局时区设置</span><br><span class="line"><span class="keyword">SELECT</span> @<span class="variable">@global</span>.time_zone;</span><br><span class="line"># 设置全局时区</span><br><span class="line"><span class="keyword">SET</span> <span class="keyword">GLOBAL</span> time_zone <span class="operator">=</span> <span class="string">&#x27;+8:00&#x27;</span>;</span><br><span class="line"><span class="keyword">SET</span> <span class="keyword">GLOBAL</span> time_zone <span class="operator">=</span> <span class="string">&#x27;Europe/Helsinki&#x27;</span>;</span><br></pre></td></tr></table></figure>
<h4 id="2-2-DateTime-类型耗费空间更大"><a href="#2-2-DateTime-类型耗费空间更大" class="headerlink" title="2.2 DateTime 类型耗费空间更大"></a>2.2 DateTime 类型耗费空间更大</h4><p>Timestamp 只需要使用 <strong>4 个字节</strong>的存储空间，但是 DateTime 需要耗费 <strong>8 个字节</strong>的存储空间。但是，这样同样造成了一个问题，<strong>Timestamp 表示的时间范围更小</strong>。</p>
<ul>
<li>DateTime ：1000-01-01 00:00:00 ~ 9999-12-31 23:59:59</li>
<li>Timestamp： 1970-01-01 00:00:01 ~ 2037-12-31 23:59:59</li>
</ul>
<blockquote>
<p>Timestamp 在不同版本的 MySQL 中有细微差别。</p>
</blockquote>
<h3 id="数值型时间戳是更好的选择吗？"><a href="#数值型时间戳是更好的选择吗？" class="headerlink" title="数值型时间戳是更好的选择吗？"></a>数值型时间戳是更好的选择吗？</h3><p>很多时候，我们也会使用 int 或者 bigint 类型的数值也就是时间戳来表示时间。</p>
<p>这种存储方式的具有 Timestamp 类型的所具有一些优点，并且使用它的进行日期排序以及对比等操作的效率会更高，跨系统也很方便，毕竟只是存放的数值。缺点也很明显，就是数据的可读性太差了，你无法直观的看到具体时间。</p>
<p>时间戳的定义如下：</p>
<blockquote>
<p>时间戳的定义是从一个基准时间开始算起，这个基准时间是「1970-1-1 00:00:00 +0:00」，从这个时间开始，用整数表示，以秒计时，随着时间的流逝这个时间整数不断增加。这样一来，我只需要一个数值，就可以完美地表示时间了，而且这个数值是一个绝对数值，即无论的身处地球的任何角落，这个表示时间的时间戳，都是一样的，生成的数值都是一样的，并且没有时区的概念，所以在系统的中时间的传输中，都不需要进行额外的转换了，只有在显示给用户的时候，才转换为字符串格式的本地时间。</p>
</blockquote>
<p>数据库中实际操作：</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> UNIX_TIMESTAMP(<span class="string">&#x27;2020-01-11 09:53:32&#x27;</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> UNIX_TIMESTAMP(<span class="string">&#x27;2020-01-11 09:53:32&#x27;</span>) <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------+</span></span><br><span class="line"><span class="operator">|</span>                            <span class="number">1578707612</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> FROM_UNIXTIME(<span class="number">1578707612</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------+</span></span><br><span class="line"><span class="operator">|</span> FROM_UNIXTIME(<span class="number">1578707612</span>) <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------+</span></span><br><span class="line"><span class="operator">|</span> <span class="number">2020</span><span class="number">-01</span><span class="number">-11</span> <span class="number">09</span>:<span class="number">53</span>:<span class="number">32</span>       <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.01</span> sec)</span><br></pre></td></tr></table></figure>
<h3 id="5-总结"><a href="#5-总结" class="headerlink" title="5.总结"></a>5.总结</h3><p>很多程序员会觉得数值型时间戳是真的好，效率又高还各种兼容，但是很多人又觉得它表现的不够直观。</p>
<hr>
<h2 id="2、隔离级别。"><a href="#2、隔离级别。" class="headerlink" title="2、隔离级别。"></a>2、隔离级别。</h2><p>可以通过下面的命令来设置隔离级别。</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SET</span> [SESSION<span class="operator">|</span><span class="keyword">GLOBAL</span>] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED<span class="operator">|</span>READ COMMITTED<span class="operator">|</span>REPEATABLE READ<span class="operator">|</span>SERIALIZABLE]</span><br></pre></td></tr></table></figure>
<p>我们再来看一下我们在下面实际操作中使用到的一些并发控制语句:</p>
<ul>
<li><code>START TARNSACTION</code> |<code>BEGIN</code>：显式地开启一个事务。</li>
<li><code>COMMIT</code>：提交事务，使得对数据库做的所有修改成为永久性。</li>
<li><code>ROLLBACK</code>：回滚会结束用户的事务，并撤销正在进行的所有未提交的修改。</li>
</ul>
<hr>
<h2 id="3、数据库连接池相关（出处：http-blog-itpub-net-9403012-viewspace-111794-）"><a href="#3、数据库连接池相关（出处：http-blog-itpub-net-9403012-viewspace-111794-）" class="headerlink" title="3、数据库连接池相关（出处：http://blog.itpub.net/9403012/viewspace-111794/）"></a>3、数据库连接池相关（出处：<a target="_blank" rel="noopener" href="http://blog.itpub.net/9403012/viewspace-111794/%EF%BC%89">http://blog.itpub.net/9403012/viewspace-111794/）</a></h2><p>Java应用程序访问数据库的基本原理</p>
<p>　　在Java语言中，JDBC（Java DataBase Connection）是应用程序与数据库沟通的桥梁,</p>
<p>　　即Java语言通过JDBC技术访问数据库。JDBC是一种“开放”的方案，它为数据库应用开发人员与数据库前台工具开发人员提供了一种标准的应用程序设计接口，使开发人员可以用纯Java语言编写完整的数据库应用程序。JDBC提供两种API，分别是面向开发人员的API和面向底层的JDBC驱动程序API，底层主要通过直接的JDBC驱动和JDBC-ODBC桥驱动实现与数据库的连接。</p>
<p>　　一般来说，Java应用程序访问数据库的过程是：</p>
<p>　　①装载数据库驱动程序；</p>
<p>　　②通过JDBC建立数据库连接；</p>
<p>　　③访问数据库，执行SQL语句；</p>
<p>　　④断开数据库连接。</p>
<p>　　JDBC作为一种数据库访问技术，具有简单易用的优点。但使用这种模式进行Web应用</p>
<p>　　程序开发，存在很多问题：首先，每一次Web请求都要建立一次数据库连接。建立连接是一个费时的活动，每次都得花费0.05s～1s的时间，而且系统还要分配内存资源。这个时间对于一次或几次数据库操作，或许感觉不出系统有多大的开销。可是对于现在的Web应用，尤其是大型电子商务网站，同时有几百人甚至几千人在线是很正常的事。在这种情况下，频繁的进行数据库连接操作势必占用很多的系统资源，网站的响应速度必定下降，严重的甚至会造成服务器的崩溃。不是危言耸听，这就是制约某些电子商务网站发展的技术瓶颈问题。其次，对于每一次数据库连接，使用完后都得断开。否则，如<strong>果程序出现异常而未能关闭，将会导致数据库系统中的内存泄漏，最终将不得不重启数据库。还有，这种开发不能控制被创建的连接对象数，系统资源会被毫无顾及的分配出去，如连接过多，也可能导致内存泄漏，服务器崩溃。</strong></p>
<p>　　数据库连接池（connection pool）的工作原理</p>
<p>　　1、基本概念及原理<br>　　由上面的分析可以看出，问题的根源就在于对数据库连接资源的低效管理。<br>　　我们知道，对于共享资源，有一个很著名的设计模式：资源池（Resource Pool）。该模式正是为了解决资源的频繁分配?释放所造成的问题。为解决上述问题，可以采用数据库连接池技术。数据库连接池的基本思想就是<strong>为数据库连接建立一个“缓冲池”</strong>。预先在缓冲池中放入一定数量的连接，当需要建立数据库连接时，只需从“缓冲池”中取出一个，使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量与使用情况，为系统开发与测试及性能调整提供依据。</p>
<p>　　2、服务器自带的连接池<br>　　JDBC的API中没有提供连接池的方法。一些大型的WEB应用服务器如BEA的WebLogic和IBM的WebSphere等提供了连接池的机制，但是必须有其第三方的专用类方法支持连接池的用法。</p>
<p>　　连接池关键问题分析</p>
<p>　　1、并发问题<br>　　为了使连接管理服务具有最大的通用性，必须考虑多线程环境，即并发问题。这个问题相对比较好解决，因为Java语言自身提供了对并发管理的支持，使用synchronized关键字即可确保线程是同步的。使用方法为<strong>直接在类方法前面加上synchronized关键字</strong>，如：</p>
<p>　　public synchronized Connection getConnection（） </p>
<p>　　2、多数据库服务器和多用户<br>　　对于大型的企业级应用，常常需要同时连接不同的数据库（如连接Oracle和Sybase）。如何连接不同的数据库呢？我们采用的策略是：<strong>设计一个符合单例模式的连接池管理类</strong>，在连接池管理类的唯一实例被创建时读取一个资源文件，其中资源文件中存放着多个数据库的url地址（）?用户名（）?密码（）等信息。如tx.url=172.21.15.123：5000/tx_it，tx.user=yang，tx.password=yang321。根据资源文件提供的信息，<strong>创建多个连接池类的实例，每一个实例都是一个特定数据库的连接池</strong>。连接池管理类实例为每个连接池实例取一个名字，通过不同的名字来管理不同的连接池。</p>
<p>　　对于同一个数据库有多个用户使用不同的名称和密码访问的情况，也可以通过资源文件处理，即在资源文件中设置多个具有相同url地址，但具有不同用户名和密码的数据库连接信息。</p>
<p>　　3、事务处理<br>　　我们知道，事务具有原子性，此时要求对数据库的操作符合“ALL-ALL-NOTHING”原则,即对于一组SQL语句要么全做，要么全不做。</p>
<p>　　在Java语言中，Connection类本身提供了对事务的支持，可以通过设置Connection的AutoCommit属性为false,然后显式的调用commit或rollback方法来实现。但要高效的进行Connection复用，就必须提供相应的事务支持机制。可采用每一个事务独占一个连接来实现，这种方法可以大大降低事务管理的复杂性。</p>
<p>　　4、连接池的分配与释放<br>　　连接池的分配与释放，对系统的性能有很大的影响。合理的分配与释放，可以提高连接的复用度，从而降低建立新连接的开销，同时还可以加快用户的访问速度。</p>
<p>　　对于连接的管理可使用空闲池。即把已经创建但尚未分配出去的连接<strong>按创建时间</strong>存放到一个空闲池中。每当用户请求一个连接时，系统首先检查空闲池内有没有空闲连接。如果有就把建立时间最长（通过容器的顺序存放实现）的那个连接分配给他（实际是先做连接是否有效的判断，如果可用就分配给用户，如不可用就把这个连接从空闲池删掉，重新检测空闲池是否还有连接）；如果没有则检查当前所开连接池是否达到连接池所允许的最大连接数（maxConn）,如果没有达到，就新建一个连接，如果已经达到，就<strong>等待一定的时间</strong>（timeout）。如果在等待的时间内有连接被释放出来就可以把这个连接分配给等待的用户，<strong>如果等待时间超过预定时间timeout,则返回空值</strong>（null）。系统对已经分配出去正在使用的连接只做计数，当使用完后再返还给空闲池。对于空闲连接的状态，<strong>可开辟专门的线程定时检测</strong>，这样会花费一定的系统开销，但可以保证较快的响应速度。也可采取不开辟专门线程，只是在分配前检测的方法。</p>
<p>　　5、连接池的配置与维护<br>　　连接池中到底应该放置多少连接，才能使系统的性能最佳？系统可采取设置<strong>最小连接数</strong>（minConn）和<strong>最大连接数</strong>（maxConn）来控制连接池中的连接。最小连接数是系统启动时连接池所创建的连接数。如果创建过多，则系统启动就慢，但创建后系统的响应速度会很快；如果创建过少，则系统启动的很快，响应起来却慢。这样，可以在开发时，设置较小的最小连接数，开发起来会快，而在系统实际使用时设置较大的，因为这样对访问客户来说速度会快些。最大连接数是连接池中允许连接的最大数目，具体设置多少，要看系统的访问量，可通过反复测试，找到最佳点。</p>
<p>　　如何确保连接池中的最小连接数呢？有动态和静态两种策略。动态即每隔一定时间就对连接池进行检测，如果发现连接数量小于最小连接数，则补充相应数量的新连接,以保证连接池的正常运转。静态是发现空闲连接不够时再去检查。</p>
<p>　　连接池的实现</p>
<p>　　1、连接池模型<br>　　本文讨论的连接池包括一个连接池类（DBConnectionPool）和一个连接池管理类（DBConnetionPoolManager）。连接池类是对某一数据库所有连接的“缓冲池”，主要实现以下功能：①从连接池<strong>获取或创建</strong>可用连接；②使用完毕之后，把连接返还给连接池；③在系统关闭前，断开所有连接并释放连接占用的系统资源；④还能够处理无效连接（原来登记为可用的连接，由于某种原因不再可用，如超时，通讯问题），并能够限制连接池中的连接总数不低于某个预定值和不超过某个预定值。</p>
<p>　　连接池管理类是连接池类的外覆类（wrapper）,<strong>符合单例模式</strong>，<strong>即系统中只能有一个连接池管理类的实例</strong>。其主要用于对多个连接池对象的管理，具有以下功能：①装载并注册特定数据库的JDBC驱动程序；②根据属性文件给定的信息，创建连接池对象；③为方便管理多个连接池对象，为每一个连接池对象取一个名字，实现连接池名字与其实例之间的映射；④跟踪客户使用连接情况，以便需要是关闭连接释放资源。连接池管理类的引入主要是为了方便对多个连接池的使用和管理，如系统需要连接不同的数据库，或连接相同的数据库但由于安全性问题，需要不同的用户使用不同的名称和密码。</p>
<p>　　2、连接池实现<br>　　下面给出连接池类和连接池管理类的主要属性及所要实现的基本接口：</p>
<p>　　public class DBConnectionPool implements TimerListener{<br>　　private int checkedOut;//已被分配出去的连接数<br>　　private ArrayList freeConnections = new ArrayList();//容器，空闲池，根据//创建时间顺序存放已创建但尚未分配出去的连接<br>　　private int minConn;//连接池里连接的最小数量<br>　　private int maxConn;//连接池里允许存在的最大连接数<br>　　private String name;//为这个连接池取个名字，方便管理<br>　　private String password;//连接数据库时需要的密码<br>　　private String url;//所要创建连接的数据库的地址<br>　　private String user;//连接数据库时需要的用户名<br>　　public Timer timer;//定时器<br>　　public DBConnectionPool(String name, String URL, String user, String<br>　　password, int maxConn)//公开的构造函数<br>　　public synchronized void freeConnection(Connection con) //使用完毕之后，//把连接返还给空闲池<br>　　public synchronized Connection getConnection(long timeout)//得到一个连接，//timeout是等待时间<br>　　public synchronized void release()//断开所有连接，释放占用的系统资源<br>　　private Connection newConnection()//新建一个数据库连接<br>　　public synchronized void TimerEvent() //定时器事件处理函数<br>　　}<br>　　public class DBConnectionManager {<br>　　static private DBConnectionManager instance;//连接池管理类的唯一实例<br>　　static private int clients;//客户数量<br>　　private ArrayList drivers = new ArrayList();//容器，存放数据库驱动程序<br>　　private HashMap pools = new HashMap ();//以name/value的形式存取连接池//对象的名字及连接池对象<br>　　static synchronized public DBConnectionManager getInstance()//如果唯一的//实例instance已经创建，直接返回这个实例;否则，调用私有构造函数，创//建连接池管理类的唯一实例<br>　　private DBConnectionManager()//私有构造函数,在其中调用初始化函数init()<br>　　public void freeConnection(String name, Connection con)// 释放一个连接，//name是一个连接池对象的名字<br>　　public Connection getConnection(String name)//从名字为name的连接池对象//中得到一个连接<br>　　public Connection getConnection(String name, long time)//从名字为name<br>　　//的连接池对象中取得一个连接，time是等待时间<br>　　public synchronized void release()//释放所有资源<br>　　private void createPools(Properties props)//根据属性文件提供的信息，创建//一个或多个连接池<br>　　private void init()//初始化连接池管理类的唯一实例，由私有构造函数调用<br>　　private void loadDrivers(Properties props)//装载数据库驱动程序<br>　　} </p>
<p>　　3、连接池使用<br>　　上面所实现的连接池在程序开发时如何应用到系统中呢？下面以Servlet为例说明连接池的使用。</p>
<p>　　Servlet的生命周期是：在开始建立servlet时，调用其初始化（<strong>init</strong>）方法。之后每个用户请求都导致一个调用前面建立的实例的<strong>service</strong>方法的线程。最后，当服务器决定卸载一个servlet时，它首先调用该servlet的 <strong>destroy</strong>方法。</p>
<p>　　根据servlet的特点，我们可以在初始化函数中生成连接池管理类的唯一实例（其中包括创建一个或多个连接池）。如：<br>　　public void init() throws ServletException<br>　　{<br>　　connMgr = DBConnectionManager.getInstance();<br>　　}<br>　　然后就可以在service方法中通过连接池名称使用连接池，执行数据库操作。最后在destroy方法中释放占用的系统资源，如：<br>public void destroy() {<br>　　connMgr.release(); super.destroy();<br>　　}<br>　　结束语<br>　　在使用JDBC进行与数据库有关的应用开发中，数据库连接的管理是一个难点。很多时候，连接的混乱管理所造成的系统资源开销过大成为制约大型企业级应用效率的瓶颈。对于众多用户访问的Web应用，采用数据库连接技术的系统在效率和稳定性上比采用传统的其他方式的系统要好很多。本文阐述了使用JDBC访问数据库的技术、讨论了基于连接池技术的数据库连接管理的关键问题并给出了一个实现模型。文章所给出的是连接池管理程序的一种基本模式，为提高系统的整体性能，在此基础上还可以进行很多有意义的扩展。</p>
<hr>
<h2 id="4、B-树、-B-树、Hash索引"><a href="#4、B-树、-B-树、Hash索引" class="headerlink" title="4、B 树、 B+树、Hash索引"></a>4、B 树、 B+树、Hash索引</h2><ul>
<li>B 树的所有节点既存放 键(key) 也存放 数据(data);而 B+树只有叶子节点存放 key 和 data，其他内节点只存放 key。</li>
<li>B 树的叶子节点都是独立的;B+树的叶子节点有一条引用链指向与它相邻的叶子节点。</li>
<li>B 树的检索的过程相当于对范围内的每个节点的关键字做二分查找，可能还没有到达叶子节点，检索就结束了。而 B+树的检索效率就很稳定了，任何查找都是从根节点到叶子节点的过程，叶子节点的顺序检索很明显。</li>
</ul>
<h4 id="Hash-索引和-B-树索引优劣分析"><a href="#Hash-索引和-B-树索引优劣分析" class="headerlink" title="Hash 索引和 B+树索引优劣分析"></a>Hash 索引和 B+树索引优劣分析</h4><p><strong>Hash 索引定位快</strong></p>
<p>Hash 索引指的就是 Hash 表，最大的优点就是能够在很短的时间内，根据 Hash 函数定位到数据所在的位置，这是 B+树所不能比的。</p>
<p><strong>Hash 冲突问题</strong></p>
<p>知道 HashMap 或 HashTable 的同学，相信都知道它们最大的缺点就是 Hash 冲突了。不过对于数据库来说这还不算最大的缺点。</p>
<p><strong>Hash 索引不支持顺序和范围查询(Hash 索引不支持顺序和范围查询是它最大的缺点。</strong></p>
<p>试想一种情况:</p>
<figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT * FROM tb1 WHERE id &lt; 500;</span><br></pre></td></tr></table></figure>
<p>B+树是有序的，在这种范围查询中，优势非常大，直接遍历比 500 小的叶子节点就够了。而 Hash 索引是根据 hash 算法来定位的，难不成还要把 1 - 499 的数据，每个都进行一次 hash 计算来定位吗?这就是 Hash 最大的缺点了。</p>
<hr>
<h2 id="5、索引类型"><a href="#5、索引类型" class="headerlink" title="5、索引类型"></a>5、索引类型</h2><h4 id="主键索引-Primary-Key"><a href="#主键索引-Primary-Key" class="headerlink" title="主键索引(Primary Key)"></a>主键索引(Primary Key)</h4><p><strong>数据表的主键列使用的就是主键索引。</strong></p>
<p><strong>一张数据表有只能有一个主键，并且主键不能为 null，不能重复。</strong></p>
<p><strong>在 mysql 的 InnoDB 的表中，当没有显示的指定表的主键时，InnoDB 会自动先检查表中是否有唯一索引的字段，如果有，则选择该字段为默认的主键，否则 InnoDB 将会自动创建一个 6Byte 的自增主键。</strong></p>
<h4 id="二级索引-辅助索引"><a href="#二级索引-辅助索引" class="headerlink" title="二级索引(辅助索引)"></a>二级索引(辅助索引)</h4><ol>
<li><strong>唯一索引(Unique Key)</strong> ：唯一索引也是一种约束。<strong>唯一索引的属性列不能出现重复的数据，但是允许数据为 NULL，一张表允许创建多个唯一索引。</strong> 建立唯一索引的目的大部分时候都是为了该属性列的数据的唯一性，而不是为了查询效率。</li>
<li><strong>普通索引(Index)</strong> ：<strong>普通索引的唯一作用就是为了快速查询数据，一张表允许创建多个普通索引，并允许数据重复和 NULL。</strong></li>
<li><strong>前缀索引(Prefix)</strong> ：前缀索引只适用于字符串类型的数据。前缀索引是对文本的前几个字符创建索引，相比普通索引建立的数据更小，<br>因为只取前几个字符。</li>
<li><strong>全文索引(Full Text)</strong> ：全文索引主要是为了检索大文本数据中的关键字的信息，是目前搜索引擎数据库使用的一种技术。Mysql5.6 之前只有 MYISAM 引擎支持全文索引，5.6 之后 InnoDB 也支持了全文索引。</li>
</ol>
<h4 id="聚集索引与非聚集索引"><a href="#聚集索引与非聚集索引" class="headerlink" title="聚集索引与非聚集索引"></a>聚集索引与非聚集索引</h4><p><strong>聚集索引</strong></p>
<p><strong>聚集索引即索引结构和数据一起存放的索引。主键索引属于聚集索引。</strong></p>
<p>在 Mysql 中，InnoDB 引擎的表的 <code>.ibd</code>文件就包含了该表的索引和数据，对于 InnoDB 引擎表来说，该表的索引(B+树)的每个非叶子节点存储索引，叶子节点存储索引和索引对应的数据。</p>
<h4 id="聚集索引的优点"><a href="#聚集索引的优点" class="headerlink" title="聚集索引的优点"></a>聚集索引的优点</h4><p>聚集索引的查询速度非常的快，因为整个 B+树本身就是一颗多叉平衡树，叶子节点也都是有序的，定位到索引的节点，就相当于定位到了数据。</p>
<h4 id="聚集索引的缺点"><a href="#聚集索引的缺点" class="headerlink" title="聚集索引的缺点"></a>聚集索引的缺点</h4><ol>
<li><strong>依赖于有序的数据</strong> ：因为 B+树是多路平衡树，如果索引的数据不是有序的，那么就需要在插入时排序，如果数据是整型还好，否则类似于字符串或 UUID 这种又长又难比较的数据，插入或查找的速度肯定比较慢。</li>
<li><strong>更新代价大</strong> ： 如果对索引列的数据被修改时，那么对应的索引也将会被修改，<br>而且况聚集索引的叶子节点还存放着数据，修改代价肯定是较大的，<br>所以对于主键索引来说，主键一般都是不可被修改的。</li>
</ol>
<h4 id="非聚集索引"><a href="#非聚集索引" class="headerlink" title="非聚集索引"></a>非聚集索引</h4><p><strong>非聚集索引即索引结构和数据分开存放的索引。</strong></p>
<p><strong>二级索引属于非聚集索引。</strong></p>
<blockquote>
<p>MYISAM 引擎的表的.MYI 文件包含了表的索引，<br>该表的索引(B+树)的每个叶子非叶子节点存储索引，<br>叶子节点存储索引和索引对应数据的指针，指向.MYD 文件的数据。</p>
<p><strong>非聚集索引的叶子节点并不一定存放数据的指针，<br>因为二级索引的叶子节点就存放的是主键，根据主键再回表查数据。</strong></p>
</blockquote>
<h4 id="非聚集索引的优点"><a href="#非聚集索引的优点" class="headerlink" title="非聚集索引的优点"></a>非聚集索引的优点</h4><p><strong>更新代价比聚集索引要小</strong> 。非聚集索引的更新代价就没有聚集索引那么大了，非聚集索引的叶子节点是不存放数据的</p>
<h4 id="非聚集索引的缺点"><a href="#非聚集索引的缺点" class="headerlink" title="非聚集索引的缺点"></a>非聚集索引的缺点</h4><ol>
<li>跟聚集索引一样，<strong>非聚集索引也依赖于有序的数据</strong></li>
<li><strong>可能会二次查询(回表)</strong> :这应该是非聚集索引最大的缺点了。 当查到索引对应的指针或主键后，可能还需要根据指针或主键再到数据文件或表中查询。</li>
</ol>
<h3 id="非聚集索引一定回表查询吗-覆盖索引"><a href="#非聚集索引一定回表查询吗-覆盖索引" class="headerlink" title="非聚集索引一定回表查询吗(覆盖索引)?"></a>非聚集索引一定回表查询吗(覆盖索引)?</h3><p><strong>非聚集索引不一定回表查询。</strong></p>
<blockquote>
<p>试想一种情况，用户准备使用 SQL 查询用户名，而用户名字段正好建立了索引。</p>
</blockquote>
<figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT name FROM table WHERE name=&#x27;guang19&#x27;;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>那么这个索引的 key 本身就是 name，查到对应的 name 直接返回就行了，无需回表查询。</p>
</blockquote>
<p><strong>即使是 MYISAM 也是这样，虽然 MYISAM 的主键索引确实需要回表，<br>因为它的主键索引的叶子节点存放的是指针。但是如果 SQL 查的就是主键呢?</strong></p>
<figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT id FROM table WHERE id=1;</span><br></pre></td></tr></table></figure>
<p>主键索引本身的 key 就是主键，查到返回就行了。这种情况就称之为覆盖索引了。</p>
<p><strong>覆盖索引即需要查询的字段正好是索引的字段，那么直接根据该索引，就可以查到数据了，<br>而无需回表查询。</strong></p>
<hr>
<h2 id="6、MySQL基础架构分析"><a href="#6、MySQL基础架构分析" class="headerlink" title="6、MySQL基础架构分析"></a>6、MySQL基础架构分析</h2><h3 id="MySQL-基本架构概览"><a href="#MySQL-基本架构概览" class="headerlink" title="MySQL 基本架构概览"></a>MySQL 基本架构概览</h3><ul>
<li><strong>连接器：</strong> 身份认证和权限相关(登录 MySQL 的时候)。</li>
<li><strong>查询缓存:</strong>  执行查询语句的时候，会先查询缓存（MySQL 8.0 版本后移除，因为这个功能不太实用）。</li>
<li><strong>分析器:</strong>  没有命中缓存的话，SQL 语句就会经过分析器，分析器说白了就是要先看你的 SQL 语句要干嘛，再检查你的 SQL 语句语法是否正确。</li>
<li><strong>优化器：</strong>  按照 MySQL 认为最优的方案去执行。</li>
<li><strong>执行器:</strong> 执行语句，然后从存储引擎返回数据。</li>
</ul>
<p>简单来说 MySQL  主要分为 Server 层和存储引擎层：</p>
<ul>
<li><strong>Server 层</strong>：主要包括连接器、查询缓存、分析器、优化器、执行器等，所有跨存储引擎的功能都在这一层实现，比如存储过程、触发器、视图，函数等，还有一个通<strong>用的日志模块 binglog 日志模块</strong>。</li>
<li><strong>存储引擎</strong>： 主要负责数据的存储和读取，采用可以替换的插件式架构，支持 InnoDB、MyISAM、Memory 等多个存储引擎，其中 InnoDB 引擎有自有的日志模块 redolog 模块。<strong>现在最常用的存储引擎是 InnoDB，它从 MySQL 5.5.5 版本开始就被当做默认存储引擎了。</strong></li>
</ul>
<h3 id="Server-层基本组件介绍"><a href="#Server-层基本组件介绍" class="headerlink" title="Server 层基本组件介绍"></a>Server 层基本组件介绍</h3><h4 id="1-连接器"><a href="#1-连接器" class="headerlink" title="1) 连接器"></a>1) 连接器</h4><p>连接器主要和身份认证和权限相关的功能相关，就好比一个级别很高的门卫一样。</p>
<p>主要负责用户登录数据库，进行用户的身份认证，包括校验账户密码，权限等操作，如果用户账户密码已通过，连接器会到权限表中查询该用户的所有权限，之后在这个连接里的权限逻辑判断都是会依赖<u>此时</u>读取到的权限数据，也就是说，后续只要这个连接不断开，即时管理员修改了该用户的权限，该用户也是不受影响的。</p>
<h4 id="2-查询缓存-MySQL-8-0-版本后移除"><a href="#2-查询缓存-MySQL-8-0-版本后移除" class="headerlink" title="2) 查询缓存(MySQL 8.0 版本后移除)"></a>2) 查询缓存(MySQL 8.0 版本后移除)</h4><p>查询缓存主要用来缓存我们所执行的 SELECT 语句以及该语句的结果集。</p>
<p>连接建立后，执行查询语句的时候，会先查询缓存，MySQL 会先校验这个 sql 是否执行过，以 Key-Value 的形式缓存在内存中，Key 是<strong>查询预计</strong>，Value 是<strong>结果集</strong>。如果缓存 key 被命中，就会直接返回给客户端，如果没有命中，就会执行后续的操作，完成后也会把结果缓存起来，方便下一次调用。当然在真正执行缓存查询的时候还是会校验用户的权限，是否有该表的查询条件。</p>
<p>MySQL 查询不建议使用缓存，因为查询缓存失效在实际业务场景中可能会非常频繁，假如你对一个表更新的话，这个表上的所有的查询缓存都会被清空。对于<strong>不经常更新</strong>的数据来说，使用缓存还是可以的。</p>
<p>所以，一般在大多数情况下我们都是不推荐去使用查询缓存的。</p>
<p>MySQL 8.0 版本后删除了缓存的功能，官方也是认为该功能在实际的应用场景比较少，所以干脆直接删掉了。</p>
<h4 id="3-分析器"><a href="#3-分析器" class="headerlink" title="3) 分析器"></a>3) 分析器</h4><p>MySQL 没有命中缓存，那么就会进入分析器，分析器主要是用来分析 SQL 语句是来干嘛的，分析器也会分为几步：</p>
<p><strong>第一步，词法分析</strong>，一条 SQL 语句有多个字符串组成，<u>首先要提取关键字</u>，比如 select，<u>提出查询的表</u>，<u>提出字段名，提出查询条件</u>等等。做完这些操作后，就会进入第二步。</p>
<p><strong>第二步，语法分析</strong>，主要就是判断你输入的 sql 是否正确，<u>是否符合 MySQL 的语法</u>。</p>
<p>完成这 2 步之后，MySQL 就准备开始执行了，但是如何执行，怎么执行是最好的结果呢？这个时候就需要优化器上场了。</p>
<h4 id="4-优化器"><a href="#4-优化器" class="headerlink" title="4) 优化器"></a>4) 优化器</h4><p>优化器的作用就是它认为的最优的执行方案去执行（有时候可能也不是最优，这篇文章涉及对这部分知识的深入讲解），比如多个索引的时候该如何选择索引，多表查询的时候如何选择关联顺序等。</p>
<p>可以说，经过了优化器之后可以说这个语句具体该如何执行就已经定下来。</p>
<h4 id="5-执行器"><a href="#5-执行器" class="headerlink" title="5) 执行器"></a>5) 执行器</h4><p>当选择了执行方案后，MySQL 就准备开始执行了，首先<u>执行前会校验该用户有没有权限</u>，如果没有权限，就会返回错误信息，如果有权限，就会去调用引擎的接口，返回接口执行的结果。</p>
<h2 id="7、语句分析"><a href="#7、语句分析" class="headerlink" title="7、语句分析"></a>7、语句分析</h2><h3 id="查询语句"><a href="#查询语句" class="headerlink" title="查询语句"></a>查询语句</h3><p>说了以上这么多，那么究竟一条 sql 语句是如何执行的呢？其实我们的 sql 可以分为两种，一种是查询，一种是更新（增加，更新，删除）。我们先分析下查询语句，语句如下：</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> tb_student  A <span class="keyword">where</span> A.age<span class="operator">=</span><span class="string">&#x27;18&#x27;</span> <span class="keyword">and</span> A.name<span class="operator">=</span><span class="string">&#x27; 张三 &#x27;</span>;</span><br></pre></td></tr></table></figure>
<p>结合上面的说明，我们分析下这个语句的执行流程：</p>
<ul>
<li><p>先检查该语句是否有权限，如果没有权限，直接返回错误信息，如果有权限，在 MySQL8.0 版本以前，会先查询缓存，以这条 sql 语句为 key 在内存中查询是否有结果，如果有直接缓存，如果没有，执行下一步。</p>
</li>
<li><p>通过分析器进行词法分析，提取 sql 语句的关键元素，比如提取上面这个语句是查询 select，提取需要查询的表名为 tb_student,需要查询所有的列，查询条件是这个表的 id=’1’。然后判断这个 sql 语句是否有语法错误，比如关键词是否正确等等，如果检查没问题就执行下一步。</p>
</li>
<li><p>接下来就是优化器进行确定执行方案，上面的 sql 语句，可以有两种执行方案：</p>
<pre><code>a.先查询学生表中姓名为“张三”的学生，然后判断是否年龄是 18。
b.先找出学生中年龄 18 岁的学生，然后再查询姓名为“张三”的学生。</code></pre>
<p>那么优化器根据自己的优化算法进行选择执行效率最好的一个方案（优化器认为，有时候不一定最好）。那么确认了执行计划后就准备开始执行了。</p>
</li>
<li><p>进行权限校验，如果没有权限就会返回错误信息，如果有权限就会调用数据库引擎接口，返回引擎的执行结果。</p>
</li>
</ul>
<h3 id="更新语句"><a href="#更新语句" class="headerlink" title="更新语句"></a>更新语句</h3><p>以上就是一条查询 sql 的执行流程，那么接下来我们看看一条更新语句如何执行的呢？sql 语句如下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">update tb_student A set A.age&#x3D;&#39;19&#39; where A.name&#x3D;&#39; 张三 &#39;;</span><br></pre></td></tr></table></figure>
<p>我们来给张三修改下年龄，在实际数据库肯定不会设置年龄这个字段的，不然要被技术负责人打的。其实条语句也基本上会沿着上一个查询的流程走，只不过<u>执行更新的时候肯定要记录日志</u>啦，这就会引入日志模块了，MySQL 自带的日志模块式 <strong>binlog（归档日志）</strong> ，所有的存储引擎都可以使用，我们常用的 InnoDB 引擎还自带了一个日志模块 <strong>redo log（重做日志）</strong>，我们就以 InnoDB 模式下来探讨这个语句的执行流程。流程如下：</p>
<ul>
<li>先查询到张三这一条数据，如果有缓存，也是会用到缓存。</li>
<li><u>然后拿到查询的语句，把 age 改为 19，然后调用引擎 API 接口，写入这一行数据，InnoDB 引擎把数据保存在内存中，同时记录 redo log，此时 redo log 进入 <code>prepare</code> 状态，然后告诉执行器，执行完成了，随时可以<strong>提交</strong>。</u></li>
<li>执行器收到通知后<u>记录 binlog</u>，然后调用引擎接口，<u>提交 redo log 为提交状态</u>。</li>
<li>更新完成。</li>
</ul>
<p><strong>这里肯定有同学会问，为什么要用两个日志模块，用一个日志模块不行吗?</strong></p>
<p>这是因为最开始 MySQL 并没与 InnoDB 引擎( InnoDB 引擎是其他公司以插件形式插入 MySQL 的) ，MySQL 自带的引擎是 MyISAM，但是我们知道 redo log 是 InnoDB 引擎特有的，其他存储引擎都没有，这就导致会没有 crash-safe 的能力(crash-safe 的能力即使数据库发生异常重启，之前提交的记录都不会丢失)，<u>binlog 日志只能用来归档</u>。</p>
<p>并不是说只用一个日志模块不可以，只是 InnoDB 引擎就是通过 redo log 来支持事务的。那么，又会有同学问，我用两个日志模块，但是不要这么复杂行不行，为什么 redo log 要引入 prepare 预提交状态？这里我们用反证法来说明下为什么要这么做？</p>
<ul>
<li><strong>先写 redo log 直接提交，然后写 binlog</strong>，假设写完 redo log 后，机器挂了，binlog 日志没有被写入，那么机器重启后，这台机器会通过 redo log 恢复数据，但是这个时候 bingog 并没有记录该数据，后续进行机器备份的时候，就会丢失这一条数据，同时主从同步也会丢失这一条数据。</li>
<li><strong>先写 binlog，然后写 redo log</strong>，假设写完了 binlog，机器异常重启了，由于没有 redo log，本机是无法恢复这一条记录的，但是 binlog 又有记录，那么和上面同样的道理，就会产生数据不一致的情况。</li>
</ul>
<p>如果采用 redo log 两阶段提交的方式就不一样了，写完 binglog 后，然后再提交 redo log 就会防止出现上述的问题，从而保证了数据的一致性。那么问题来了，有没有一个极端的情况呢？假设 redo log 处于预提交状态，binglog 也已经写完了，这个时候发生了异常重启会怎么样呢？<br>这个就要依赖于 MySQL 的处理机制了，MySQL 的处理过程如下：</p>
<ul>
<li>判断 redo log 是否完整，如果判断是完整的，就立即提交。</li>
<li>如果 redo log 只是预提交但不是 commit 状态，这个时候就会去判断 binlog 是否完整，如果完整就提交 redo log, 不完整就<strong>回滚事务</strong>。</li>
</ul>
<p>这样就解决了数据一致性的问题。</p>
<ul>
<li>MySQL 主要分为 Server 层和引擎层，Server 层主要包括连接器、查询缓存、分析器、优化器、执行器，同时还有一个<strong>日志模块</strong>（binlog），这个日志模块所有执行引擎都可以共用,<strong>redolog 只有 InnoDB</strong> 有。</li>
<li><strong>引擎层是插件式的</strong>，目前主要包括，MyISAM,InnoDB,Memory 等。</li>
<li>查询语句的执行流程如下：权限校验（如果命中缓存）—》查询缓存—》分析器—》优化器—》<strong>权限校验</strong>—》执行器—》引擎</li>
<li>更新语句执行流程如下：分析器—-》权限校验—-》执行器—》引擎—redo log(prepare 状态—》binlog—》redo log(commit状态)</li>
</ul>
<hr>
<h2 id="8、数据类型-列类型"><a href="#8、数据类型-列类型" class="headerlink" title="8、数据类型(列类型)"></a>8、数据类型(列类型)</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;* 数据类型（列类型） *&#x2F; ------------------</span><br><span class="line">1. 数值类型</span><br><span class="line">-- a. 整型 ----------</span><br><span class="line">    类型         字节     范围（有符号位）</span><br><span class="line">    tinyint     1字节    -128 ~ 127      无符号位：0 ~ 255</span><br><span class="line">    smallint    2字节    -32768 ~ 32767</span><br><span class="line">    mediumint   3字节    -8388608 ~ 8388607</span><br><span class="line">    int         4字节</span><br><span class="line">    bigint      8字节</span><br><span class="line">    int(M)  M表示总位数</span><br><span class="line">    - 默认存在符号位，unsigned 属性修改</span><br><span class="line">    - 显示宽度，如果某个数不够定义字段时设置的位数，则前面以0补填，zerofill 属性修改</span><br><span class="line">        例：int(5)   插入一个数&#39;123&#39;，补填后为&#39;00123&#39;</span><br><span class="line">    - 在满足要求的情况下，越小越好。</span><br><span class="line">    - 1表示bool值真，0表示bool值假。MySQL没有布尔类型，通过整型0和1表示。常用tinyint(1)表示布尔型。</span><br><span class="line">-- b. 浮点型 ----------</span><br><span class="line">    类型             字节     范围</span><br><span class="line">    float(单精度)     4字节</span><br><span class="line">    double(双精度)    8字节</span><br><span class="line">    浮点型既支持符号位 unsigned 属性，也支持显示宽度 zerofill 属性。</span><br><span class="line">        不同于整型，前后均会补填0.</span><br><span class="line">    定义浮点型时，需指定总位数和小数位数。</span><br><span class="line">        float(M, D)     double(M, D)</span><br><span class="line">        M表示总位数，D表示小数位数。</span><br><span class="line">        M和D的大小会决定浮点数的范围。不同于整型的固定范围。</span><br><span class="line">        M既表示总位数（不包括小数点和正负号），也表示显示宽度（所有显示符号均包括）。</span><br><span class="line">        支持科学计数法表示。</span><br><span class="line">        浮点数表示近似值。</span><br><span class="line">-- c. 定点数 ----------</span><br><span class="line">    decimal -- 可变长度</span><br><span class="line">    decimal(M, D)   M也表示总位数，D表示小数位数。</span><br><span class="line">    保存一个精确的数值，不会发生数据的改变，不同于浮点数的四舍五入。</span><br><span class="line">    将浮点数转换为字符串来保存，每9位数字保存为4个字节。</span><br><span class="line">2. 字符串类型</span><br><span class="line">-- a. char, varchar ----------</span><br><span class="line">    char    定长字符串，速度快，但浪费空间</span><br><span class="line">    varchar 变长字符串，速度慢，但节省空间</span><br><span class="line">    M表示能存储的最大长度，此长度是字符数，非字节数。</span><br><span class="line">    不同的编码，所占用的空间不同。</span><br><span class="line">    char,最多255个字符，与编码无关。</span><br><span class="line">    varchar,最多65535字符，与编码有关。</span><br><span class="line">    一条有效记录最大不能超过65535个字节。</span><br><span class="line">        utf8 最大为21844个字符，gbk 最大为32766个字符，latin1 最大为65532个字符</span><br><span class="line">    varchar 是变长的，需要利用存储空间保存 varchar 的长度，如果数据小于255个字节，则采用一个字节来保存长度，反之需要两个字节来保存。</span><br><span class="line">    varchar 的最大有效长度由最大行大小和使用的字符集确定。</span><br><span class="line">    最大有效长度是65532字节，因为在varchar存字符串时，第一个字节是空的，不存在任何数据，然后还需两个字节来存放字符串的长度，所以有效长度是65535-1-2&#x3D;65532字节。</span><br><span class="line">    例：若一个表定义为 CREATE TABLE tb(c1 int, c2 char(30), c3 varchar(N)) charset&#x3D;utf8; 问N的最大值是多少？ 答：(65535-1-2-4-30*3)&#x2F;3</span><br><span class="line">-- b. blob, text ----------</span><br><span class="line">    blob 二进制字符串（字节字符串）</span><br><span class="line">        tinyblob, blob, mediumblob, longblob</span><br><span class="line">    text 非二进制字符串（字符字符串）</span><br><span class="line">        tinytext, text, mediumtext, longtext</span><br><span class="line">    text 在定义时，不需要定义长度，也不会计算总长度。</span><br><span class="line">    text 类型在定义时，不可给default值</span><br><span class="line">-- c. binary, varbinary ----------</span><br><span class="line">    类似于char和varchar，用于保存二进制字符串，也就是保存字节字符串而非字符字符串。</span><br><span class="line">    char, varchar, text 对应 binary, varbinary, blob.</span><br><span class="line">3. 日期时间类型</span><br><span class="line">    一般用整型保存时间戳，因为PHP可以很方便的将时间戳进行格式化。</span><br><span class="line">    datetime    8字节    日期及时间     1000-01-01 00:00:00 到 9999-12-31 23:59:59</span><br><span class="line">    date        3字节    日期         1000-01-01 到 9999-12-31</span><br><span class="line">    timestamp   4字节    时间戳        19700101000000 到 2038-01-19 03:14:07</span><br><span class="line">    time        3字节    时间         -838:59:59 到 838:59:59</span><br><span class="line">    year        1字节    年份         1901 - 2155</span><br><span class="line">datetime    YYYY-MM-DD hh:mm:ss</span><br><span class="line">timestamp   YY-MM-DD hh:mm:ss</span><br><span class="line">            YYYYMMDDhhmmss</span><br><span class="line">            YYMMDDhhmmss</span><br><span class="line">            YYYYMMDDhhmmss</span><br><span class="line">            YYMMDDhhmmss</span><br><span class="line">date        YYYY-MM-DD</span><br><span class="line">            YY-MM-DD</span><br><span class="line">            YYYYMMDD</span><br><span class="line">            YYMMDD</span><br><span class="line">            YYYYMMDD</span><br><span class="line">            YYMMDD</span><br><span class="line">time        hh:mm:ss</span><br><span class="line">            hhmmss</span><br><span class="line">            hhmmss</span><br><span class="line">year        YYYY</span><br><span class="line">            YY</span><br><span class="line">            YYYY</span><br><span class="line">            YY</span><br><span class="line">4. 枚举和集合</span><br><span class="line">-- 枚举(enum) ----------</span><br><span class="line">enum(val1, val2, val3...)</span><br><span class="line">    在已知的值中进行单选。最大数量为65535.</span><br><span class="line">    枚举值在保存时，以2个字节的整型(smallint)保存。每个枚举值，按保存的位置顺序，从1开始逐一递增。</span><br><span class="line">    表现为字符串类型，存储却是整型。</span><br><span class="line">    NULL值的索引是NULL。</span><br><span class="line">    空字符串错误值的索引值是0。</span><br><span class="line">-- 集合（set） ----------</span><br><span class="line">set(val1, val2, val3...)</span><br><span class="line">    create table tab ( gender set(&#39;男&#39;, &#39;女&#39;, &#39;无&#39;) );</span><br><span class="line">    insert into tab values (&#39;男, 女&#39;);</span><br><span class="line">    最多可以有64个不同的成员。以bigint存储，共8个字节。采取位运算的形式。</span><br><span class="line">    当创建表时，SET成员值的尾部空格将自动被删除。</span><br></pre></td></tr></table></figure>
<hr>
<h2 id="9、表的操作"><a href="#9、表的操作" class="headerlink" title="9、表的操作"></a>9、表的操作</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line">-- 创建表</span><br><span class="line">    CREATE [TEMPORARY] TABLE[ IF NOT EXISTS] [库名.]表名 ( 表的结构定义 )[ 表选项]</span><br><span class="line">        每个字段必须有数据类型</span><br><span class="line">        最后一个字段后不能有逗号</span><br><span class="line">        TEMPORARY 临时表，会话结束时表自动消失</span><br><span class="line">        对于字段的定义：</span><br><span class="line">            字段名 数据类型 [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT &#39;string&#39;]</span><br><span class="line">-- 表选项</span><br><span class="line">    -- 字符集</span><br><span class="line">        CHARSET &#x3D; charset_name</span><br><span class="line">        如果表没有设定，则使用数据库字符集</span><br><span class="line">    -- 存储引擎</span><br><span class="line">        ENGINE &#x3D; engine_name</span><br><span class="line">        表在管理数据时采用的不同的数据结构，结构不同会导致处理方式、提供的特性操作等不同</span><br><span class="line">        常见的引擎：InnoDB MyISAM Memory&#x2F;Heap BDB Merge Example CSV MaxDB Archive</span><br><span class="line">        不同的引擎在保存表的结构和数据时采用不同的方式</span><br><span class="line">        MyISAM表文件含义：.frm表定义，.MYD表数据，.MYI表索引</span><br><span class="line">        InnoDB表文件含义：.frm表定义，表空间数据和日志文件</span><br><span class="line">        SHOW ENGINES -- 显示存储引擎的状态信息</span><br><span class="line">        SHOW ENGINE 引擎名 &#123;LOGS|STATUS&#125; -- 显示存储引擎的日志或状态信息</span><br><span class="line">    -- 自增起始数</span><br><span class="line">    	AUTO_INCREMENT &#x3D; 行数</span><br><span class="line">    -- 数据文件目录</span><br><span class="line">        DATA DIRECTORY &#x3D; &#39;目录&#39;</span><br><span class="line">    -- 索引文件目录</span><br><span class="line">        INDEX DIRECTORY &#x3D; &#39;目录&#39;</span><br><span class="line">    -- 表注释</span><br><span class="line">        COMMENT &#x3D; &#39;string&#39;</span><br><span class="line">    -- 分区选项</span><br><span class="line">        PARTITION BY ... (详细见手册)</span><br><span class="line">-- 查看所有表</span><br><span class="line">    SHOW TABLES[ LIKE &#39;pattern&#39;]</span><br><span class="line">    SHOW TABLES FROM  库名</span><br><span class="line">-- 查看表结构</span><br><span class="line">    SHOW CREATE TABLE 表名 （信息更详细）</span><br><span class="line">    DESC 表名 &#x2F; DESCRIBE 表名 &#x2F; EXPLAIN 表名 &#x2F; SHOW COLUMNS FROM 表名 [LIKE &#39;PATTERN&#39;]</span><br><span class="line">    SHOW TABLE STATUS [FROM db_name] [LIKE &#39;pattern&#39;]</span><br><span class="line">-- 修改表</span><br><span class="line">    -- 修改表本身的选项</span><br><span class="line">        ALTER TABLE 表名 表的选项</span><br><span class="line">        eg: ALTER TABLE 表名 ENGINE&#x3D;MYISAM;</span><br><span class="line">    -- 对表进行重命名</span><br><span class="line">        RENAME TABLE 原表名 TO 新表名</span><br><span class="line">        RENAME TABLE 原表名 TO 库名.表名 （可将表移动到另一个数据库）</span><br><span class="line">        -- RENAME可以交换两个表名</span><br><span class="line">    -- 修改表的字段机构（13.1.2. ALTER TABLE语法）</span><br><span class="line">        ALTER TABLE 表名 操作名</span><br><span class="line">        -- 操作名</span><br><span class="line">            ADD[ COLUMN] 字段定义       -- 增加字段</span><br><span class="line">                AFTER 字段名          -- 表示增加在该字段名后面</span><br><span class="line">                FIRST               -- 表示增加在第一个</span><br><span class="line">            ADD PRIMARY KEY(字段名)   -- 创建主键</span><br><span class="line">            ADD UNIQUE [索引名] (字段名)-- 创建唯一索引</span><br><span class="line">            ADD INDEX [索引名] (字段名) -- 创建普通索引</span><br><span class="line">            DROP[ COLUMN] 字段名      -- 删除字段</span><br><span class="line">            MODIFY[ COLUMN] 字段名 字段属性     -- 支持对字段属性进行修改，不能修改字段名(所有原有属性也需写上)</span><br><span class="line">            CHANGE[ COLUMN] 原字段名 新字段名 字段属性      -- 支持对字段名修改</span><br><span class="line">            DROP PRIMARY KEY    -- 删除主键(删除主键前需删除其AUTO_INCREMENT属性)</span><br><span class="line">            DROP INDEX 索引名 -- 删除索引</span><br><span class="line">            DROP FOREIGN KEY 外键    -- 删除外键</span><br><span class="line">-- 删除表</span><br><span class="line">    DROP TABLE[ IF EXISTS] 表名 ...</span><br><span class="line">-- 清空表数据</span><br><span class="line">    TRUNCATE [TABLE] 表名</span><br><span class="line">-- 复制表结构</span><br><span class="line">    CREATE TABLE 表名 LIKE 要复制的表名</span><br><span class="line">-- 复制表结构和数据</span><br><span class="line">    CREATE TABLE 表名 [AS] SELECT * FROM 要复制的表名</span><br><span class="line">-- 检查表是否有错误</span><br><span class="line">    CHECK TABLE tbl_name [, tbl_name] ... [option] ...</span><br><span class="line">-- 优化表</span><br><span class="line">    OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...</span><br><span class="line">-- 修复表</span><br><span class="line">    REPAIR [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ... [QUICK] [EXTENDED] [USE_FRM]</span><br><span class="line">-- 分析表</span><br><span class="line">    ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...</span><br></pre></td></tr></table></figure>
<hr>
<h2 id="10、列属性-列约束"><a href="#10、列属性-列约束" class="headerlink" title="10、列属性(列约束)"></a>10、列属性(列约束)</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;* 列属性（列约束） *&#x2F; ------------------</span><br><span class="line">1. PRIMARY 主键</span><br><span class="line">    - 能唯一标识记录的字段，可以作为主键。</span><br><span class="line">    - 一个表只能有一个主键。</span><br><span class="line">    - 主键具有唯一性。</span><br><span class="line">    - 声明字段时，用 primary key 标识。</span><br><span class="line">        也可以在字段列表之后声明</span><br><span class="line">            例：create table tab ( id int, stu varchar(10), primary key (id));</span><br><span class="line">    - 主键字段的值不能为null。</span><br><span class="line">    - 主键可以由多个字段共同组成。此时需要在字段列表后声明的方法。</span><br><span class="line">        例：create table tab ( id int, stu varchar(10), age int, primary key (stu, age));</span><br><span class="line">2. UNIQUE 唯一索引（唯一约束）</span><br><span class="line">    使得某字段的值也不能重复。</span><br><span class="line">3. NULL 约束</span><br><span class="line">    null不是数据类型，是列的一个属性。</span><br><span class="line">    表示当前列是否可以为null，表示什么都没有。</span><br><span class="line">    null, 允许为空。默认。</span><br><span class="line">    not null, 不允许为空。</span><br><span class="line">    insert into tab values (null, &#39;val&#39;);</span><br><span class="line">        -- 此时表示将第一个字段的值设为null, 取决于该字段是否允许为null</span><br><span class="line">4. DEFAULT 默认值属性</span><br><span class="line">    当前字段的默认值。</span><br><span class="line">    insert into tab values (default, &#39;val&#39;);    -- 此时表示强制使用默认值。</span><br><span class="line">    create table tab ( add_time timestamp default current_timestamp );</span><br><span class="line">        -- 表示将当前时间的时间戳设为默认值。</span><br><span class="line">        current_date, current_time</span><br><span class="line">5. AUTO_INCREMENT 自动增长约束</span><br><span class="line">    自动增长必须为索引（主键或unique）</span><br><span class="line">    只能存在一个字段为自动增长。</span><br><span class="line">    默认为1开始自动增长。可以通过表属性 auto_increment &#x3D; x进行设置，或 alter table tbl auto_increment &#x3D; x;</span><br><span class="line">6. COMMENT 注释</span><br><span class="line">    例：create table tab ( id int ) comment &#39;注释内容&#39;;</span><br><span class="line">7. FOREIGN KEY 外键约束</span><br><span class="line">    用于限制主表与从表数据完整性。</span><br><span class="line">    alter table t1 add constraint &#96;t1_t2_fk&#96; foreign key (t1_id) references t2(id);</span><br><span class="line">        -- 将表t1的t1_id外键关联到表t2的id字段。</span><br><span class="line">        -- 每个外键都有一个名字，可以通过 constraint 指定</span><br><span class="line">    存在外键的表，称之为从表（子表），外键指向的表，称之为主表（父表）。</span><br><span class="line">    作用：保持数据一致性，完整性，主要目的是控制存储在外键表（从表）中的数据。</span><br><span class="line">    MySQL中，可以对InnoDB引擎使用外键约束：</span><br><span class="line">    语法：</span><br><span class="line">    foreign key (外键字段） references 主表名 (关联字段) [主表记录删除时的动作] [主表记录更新时的动作]</span><br><span class="line">    此时需要检测一个从表的外键需要约束为主表的已存在的值。外键在没有关联的情况下，可以设置为null.前提是该外键列，没有not null。</span><br><span class="line">    可以不指定主表记录更改或更新时的动作，那么此时主表的操作被拒绝。</span><br><span class="line">    如果指定了 on update 或 on delete：在删除或更新时，有如下几个操作可以选择：</span><br><span class="line">    1. cascade，级联操作。主表数据被更新（主键值更新），从表也被更新（外键值更新）。主表记录被删除，从表相关记录也被删除。</span><br><span class="line">    2. set null，设置为null。主表数据被更新（主键值更新），从表的外键被设置为null。主表记录被删除，从表相关记录外键被设置成null。但注意，要求该外键列，没有not null属性约束。</span><br><span class="line">    3. restrict，拒绝父表删除和更新。</span><br><span class="line">    注意，外键只被InnoDB存储引擎所支持。其他引擎是不支持的。</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<hr>
<h2 id="11、建表规范"><a href="#11、建表规范" class="headerlink" title="11、建表规范"></a>11、建表规范</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;* 建表规范 *&#x2F; ------------------</span><br><span class="line">    -- Normal Format, NF</span><br><span class="line">        - 每个表保存一个实体信息</span><br><span class="line">        - 每个具有一个ID字段作为主键</span><br><span class="line">        - ID主键 + 原子表</span><br><span class="line">    -- 1NF, 第一范式</span><br><span class="line">        字段不能再分，就满足第一范式。</span><br><span class="line">    -- 2NF, 第二范式</span><br><span class="line">        满足第一范式的前提下，不能出现部分依赖。</span><br><span class="line">        消除复合主键就可以避免部分依赖。增加单列关键字。</span><br><span class="line">    -- 3NF, 第三范式</span><br><span class="line">        满足第二范式的前提下，不能出现传递依赖。</span><br><span class="line">        某个字段依赖于主键，而有其他字段依赖于该字段。这就是传递依赖。</span><br><span class="line">        将一个实体信息的数据放在一个表内实现。</span><br></pre></td></tr></table></figure>
<hr>
<h2 id="12、SELECT"><a href="#12、SELECT" class="headerlink" title="12、SELECT"></a>12、SELECT</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;* SELECT *&#x2F; ------------------</span><br><span class="line">SELECT [ALL|DISTINCT] select_expr FROM -&gt; WHERE -&gt; GROUP BY [合计函数] -&gt; HAVING -&gt; ORDER BY -&gt; LIMIT</span><br><span class="line">a. select_expr</span><br><span class="line">    -- 可以用 * 表示所有字段。</span><br><span class="line">        select * from tb;</span><br><span class="line">    -- 可以使用表达式（计算公式、函数调用、字段也是个表达式）</span><br><span class="line">        select stu, 29+25, now() from tb;</span><br><span class="line">    -- 可以为每个列使用别名。适用于简化列标识，避免多个列标识符重复。</span><br><span class="line">        - 使用 as 关键字，也可省略 as.</span><br><span class="line">        select stu+10 as add10 from tb;</span><br><span class="line">b. FROM 子句</span><br><span class="line">    用于标识查询来源。</span><br><span class="line">    -- 可以为表起别名。使用as关键字。</span><br><span class="line">        SELECT * FROM tb1 AS tt, tb2 AS bb;</span><br><span class="line">    -- from子句后，可以同时出现多个表。</span><br><span class="line">        -- 多个表会横向叠加到一起，而数据会形成一个笛卡尔积。</span><br><span class="line">        SELECT * FROM tb1, tb2;</span><br><span class="line">    -- 向优化符提示如何选择索引</span><br><span class="line">        USE INDEX、IGNORE INDEX、FORCE INDEX</span><br><span class="line">        SELECT * FROM table1 USE INDEX (key1,key2) WHERE key1&#x3D;1 AND key2&#x3D;2 AND key3&#x3D;3;</span><br><span class="line">        SELECT * FROM table1 IGNORE INDEX (key3) WHERE key1&#x3D;1 AND key2&#x3D;2 AND key3&#x3D;3;</span><br><span class="line">c. WHERE 子句</span><br><span class="line">    -- 从from获得的数据源中进行筛选。</span><br><span class="line">    -- 整型1表示真，0表示假。</span><br><span class="line">    -- 表达式由运算符和运算数组成。</span><br><span class="line">        -- 运算数：变量（字段）、值、函数返回值</span><br><span class="line">        -- 运算符：</span><br><span class="line">            &#x3D;, &lt;&#x3D;&gt;, &lt;&gt;, !&#x3D;, &lt;&#x3D;, &lt;, &gt;&#x3D;, &gt;, !, &amp;&amp;, ||,</span><br><span class="line">            in (not) null, (not) like, (not) in, (not) between and, is (not), and, or, not, xor</span><br><span class="line">            is&#x2F;is not 加上ture&#x2F;false&#x2F;unknown，检验某个值的真假</span><br><span class="line">            &lt;&#x3D;&gt;与&lt;&gt;功能相同，&lt;&#x3D;&gt;可用于null比较</span><br><span class="line">d. GROUP BY 子句, 分组子句</span><br><span class="line">    GROUP BY 字段&#x2F;别名 [排序方式]</span><br><span class="line">    分组后会进行排序。升序：ASC，降序：DESC</span><br><span class="line">    以下[合计函数]需配合 GROUP BY 使用：</span><br><span class="line">    count 返回不同的非NULL值数目  count(*)、count(字段)</span><br><span class="line">    sum 求和</span><br><span class="line">    max 求最大值</span><br><span class="line">    min 求最小值</span><br><span class="line">    avg 求平均值</span><br><span class="line">    group_concat 返回带有来自一个组的连接的非NULL值的字符串结果。组内字符串连接。</span><br><span class="line">e. HAVING 子句，条件子句</span><br><span class="line">    与 where 功能、用法相同，执行时机不同。</span><br><span class="line">    where 在开始时执行检测数据，对原数据进行过滤。</span><br><span class="line">    having 对筛选出的结果再次进行过滤。</span><br><span class="line">    having 字段必须是查询出来的，where 字段必须是数据表存在的。</span><br><span class="line">    where 不可以使用字段的别名，having 可以。因为执行WHERE代码时，可能尚未确定列值。</span><br><span class="line">    where 不可以使用合计函数。一般需用合计函数才会用 having</span><br><span class="line">    SQL标准要求HAVING必须引用GROUP BY子句中的列或用于合计函数中的列。</span><br><span class="line">f. ORDER BY 子句，排序子句</span><br><span class="line">    order by 排序字段&#x2F;别名 排序方式 [,排序字段&#x2F;别名 排序方式]...</span><br><span class="line">    升序：ASC，降序：DESC</span><br><span class="line">    支持多个字段的排序。</span><br><span class="line">g. LIMIT 子句，限制结果数量子句</span><br><span class="line">    仅对处理好的结果进行数量限制。将处理好的结果的看作是一个集合，按照记录出现的顺序，索引从0开始。</span><br><span class="line">    limit 起始位置, 获取条数</span><br><span class="line">    省略第一个参数，表示从索引0开始。limit 获取条数</span><br><span class="line">h. DISTINCT, ALL 选项</span><br><span class="line">    distinct 去除重复记录</span><br><span class="line">    默认为 all, 全部记录</span><br></pre></td></tr></table></figure>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="mailto:undefined">蔡哞哞</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://caixm1025.gitee.io/2021/03/06/03-05%E6%95%B0%E6%8D%AE%E5%BA%93%E5%AD%A6%E4%B9%A0/">https://caixm1025.gitee.io/2021/03/06/03-05%E6%95%B0%E6%8D%AE%E5%BA%93%E5%AD%A6%E4%B9%A0/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://caixm1025.gitee.io" target="_blank">个人博客</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/everyday/tags/MySQL/">MySQL</a></div><div class="post_share"><div class="social-share" data-image="/everyday/img/%E5%9B%BE%E7%89%875.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/social-share.js/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/social-share.js/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/everyday/2021/04/09/04-09%E7%AE%97%E6%B3%95%E5%AD%A6%E4%B9%A0/"><img class="prev-cover" src="/everyday/img/%E5%9B%BE%E7%89%879.jpg" onerror="onerror=null;src='/everyday/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">04-09算法学习</div></div></a></div><div class="next-post pull-right"><a href="/everyday/2021/03/04/03-04%E6%95%B0%E6%8D%AE%E5%BA%93%E5%AD%A6%E4%B9%A0/"><img class="next-cover" src="/everyday/img/%E5%9B%BE%E7%89%874.jpg" onerror="onerror=null;src='/everyday/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">03-04数据库学习</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span> 相关推荐</span></div><div class="relatedPosts-list"><div><a href="/everyday/2021/02/26/02-26数据库学习/" title="02-26数据库学习"><img class="cover" src="/everyday/img/%E5%9B%BE%E7%89%8726.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-02-26</div><div class="title">02-26数据库学习</div></div></a></div><div><a href="/everyday/2021/03/04/03-04数据库学习/" title="03-04数据库学习"><img class="cover" src="/everyday/img/%E5%9B%BE%E7%89%874.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-03-04</div><div class="title">03-04数据库学习</div></div></a></div></div></div></div><div class="aside-content" id="aside-content"><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%85%A8%E6%96%87%E7%BB%9D%E5%A4%A7%E9%83%A8%E5%88%86%E5%86%85%E5%AE%B9%E6%9D%A5%E8%87%AA%EF%BC%9Ahttps-gitee-com-SnailClimb-JavaGuide"><span class="toc-number">1.</span> <span class="toc-text">全文绝大部分内容来自：https:&#x2F;&#x2F;gitee.com&#x2F;SnailClimb&#x2F;JavaGuide</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81Datetime-%E5%92%8C-Timestamp"><span class="toc-number">1.1.</span> <span class="toc-text">1、Datetime 和 Timestamp</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-DateTime-%E7%B1%BB%E5%9E%8B%E8%80%97%E8%B4%B9%E7%A9%BA%E9%97%B4%E6%9B%B4%E5%A4%A7"><span class="toc-number">1.1.0.1.</span> <span class="toc-text">2.2 DateTime 类型耗费空间更大</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%95%B0%E5%80%BC%E5%9E%8B%E6%97%B6%E9%97%B4%E6%88%B3%E6%98%AF%E6%9B%B4%E5%A5%BD%E7%9A%84%E9%80%89%E6%8B%A9%E5%90%97%EF%BC%9F"><span class="toc-number">1.1.1.</span> <span class="toc-text">数值型时间戳是更好的选择吗？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-%E6%80%BB%E7%BB%93"><span class="toc-number">1.1.2.</span> <span class="toc-text">5.总结</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E3%80%82"><span class="toc-number">1.2.</span> <span class="toc-text">2、隔离级别。</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E6%B1%A0%E7%9B%B8%E5%85%B3%EF%BC%88%E5%87%BA%E5%A4%84%EF%BC%9Ahttp-blog-itpub-net-9403012-viewspace-111794-%EF%BC%89"><span class="toc-number">1.3.</span> <span class="toc-text">3、数据库连接池相关（出处：http:&#x2F;&#x2F;blog.itpub.net&#x2F;9403012&#x2F;viewspace-111794&#x2F;）</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4%E3%80%81B-%E6%A0%91%E3%80%81-B-%E6%A0%91%E3%80%81Hash%E7%B4%A2%E5%BC%95"><span class="toc-number">1.4.</span> <span class="toc-text">4、B 树、 B+树、Hash索引</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Hash-%E7%B4%A2%E5%BC%95%E5%92%8C-B-%E6%A0%91%E7%B4%A2%E5%BC%95%E4%BC%98%E5%8A%A3%E5%88%86%E6%9E%90"><span class="toc-number">1.4.0.1.</span> <span class="toc-text">Hash 索引和 B+树索引优劣分析</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5%E3%80%81%E7%B4%A2%E5%BC%95%E7%B1%BB%E5%9E%8B"><span class="toc-number">1.5.</span> <span class="toc-text">5、索引类型</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%B8%BB%E9%94%AE%E7%B4%A2%E5%BC%95-Primary-Key"><span class="toc-number">1.5.0.1.</span> <span class="toc-text">主键索引(Primary Key)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BA%8C%E7%BA%A7%E7%B4%A2%E5%BC%95-%E8%BE%85%E5%8A%A9%E7%B4%A2%E5%BC%95"><span class="toc-number">1.5.0.2.</span> <span class="toc-text">二级索引(辅助索引)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%81%9A%E9%9B%86%E7%B4%A2%E5%BC%95%E4%B8%8E%E9%9D%9E%E8%81%9A%E9%9B%86%E7%B4%A2%E5%BC%95"><span class="toc-number">1.5.0.3.</span> <span class="toc-text">聚集索引与非聚集索引</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%81%9A%E9%9B%86%E7%B4%A2%E5%BC%95%E7%9A%84%E4%BC%98%E7%82%B9"><span class="toc-number">1.5.0.4.</span> <span class="toc-text">聚集索引的优点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%81%9A%E9%9B%86%E7%B4%A2%E5%BC%95%E7%9A%84%E7%BC%BA%E7%82%B9"><span class="toc-number">1.5.0.5.</span> <span class="toc-text">聚集索引的缺点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%9D%9E%E8%81%9A%E9%9B%86%E7%B4%A2%E5%BC%95"><span class="toc-number">1.5.0.6.</span> <span class="toc-text">非聚集索引</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%9D%9E%E8%81%9A%E9%9B%86%E7%B4%A2%E5%BC%95%E7%9A%84%E4%BC%98%E7%82%B9"><span class="toc-number">1.5.0.7.</span> <span class="toc-text">非聚集索引的优点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%9D%9E%E8%81%9A%E9%9B%86%E7%B4%A2%E5%BC%95%E7%9A%84%E7%BC%BA%E7%82%B9"><span class="toc-number">1.5.0.8.</span> <span class="toc-text">非聚集索引的缺点</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%9D%9E%E8%81%9A%E9%9B%86%E7%B4%A2%E5%BC%95%E4%B8%80%E5%AE%9A%E5%9B%9E%E8%A1%A8%E6%9F%A5%E8%AF%A2%E5%90%97-%E8%A6%86%E7%9B%96%E7%B4%A2%E5%BC%95"><span class="toc-number">1.5.1.</span> <span class="toc-text">非聚集索引一定回表查询吗(覆盖索引)?</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6%E3%80%81MySQL%E5%9F%BA%E7%A1%80%E6%9E%B6%E6%9E%84%E5%88%86%E6%9E%90"><span class="toc-number">1.6.</span> <span class="toc-text">6、MySQL基础架构分析</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#MySQL-%E5%9F%BA%E6%9C%AC%E6%9E%B6%E6%9E%84%E6%A6%82%E8%A7%88"><span class="toc-number">1.6.1.</span> <span class="toc-text">MySQL 基本架构概览</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Server-%E5%B1%82%E5%9F%BA%E6%9C%AC%E7%BB%84%E4%BB%B6%E4%BB%8B%E7%BB%8D"><span class="toc-number">1.6.2.</span> <span class="toc-text">Server 层基本组件介绍</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-%E8%BF%9E%E6%8E%A5%E5%99%A8"><span class="toc-number">1.6.2.1.</span> <span class="toc-text">1) 连接器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-%E6%9F%A5%E8%AF%A2%E7%BC%93%E5%AD%98-MySQL-8-0-%E7%89%88%E6%9C%AC%E5%90%8E%E7%A7%BB%E9%99%A4"><span class="toc-number">1.6.2.2.</span> <span class="toc-text">2) 查询缓存(MySQL 8.0 版本后移除)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-%E5%88%86%E6%9E%90%E5%99%A8"><span class="toc-number">1.6.2.3.</span> <span class="toc-text">3) 分析器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-%E4%BC%98%E5%8C%96%E5%99%A8"><span class="toc-number">1.6.2.4.</span> <span class="toc-text">4) 优化器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-%E6%89%A7%E8%A1%8C%E5%99%A8"><span class="toc-number">1.6.2.5.</span> <span class="toc-text">5) 执行器</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7%E3%80%81%E8%AF%AD%E5%8F%A5%E5%88%86%E6%9E%90"><span class="toc-number">1.7.</span> <span class="toc-text">7、语句分析</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5"><span class="toc-number">1.7.1.</span> <span class="toc-text">查询语句</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9B%B4%E6%96%B0%E8%AF%AD%E5%8F%A5"><span class="toc-number">1.7.2.</span> <span class="toc-text">更新语句</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8%E3%80%81%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B-%E5%88%97%E7%B1%BB%E5%9E%8B"><span class="toc-number">1.8.</span> <span class="toc-text">8、数据类型(列类型)</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#9%E3%80%81%E8%A1%A8%E7%9A%84%E6%93%8D%E4%BD%9C"><span class="toc-number">1.9.</span> <span class="toc-text">9、表的操作</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10%E3%80%81%E5%88%97%E5%B1%9E%E6%80%A7-%E5%88%97%E7%BA%A6%E6%9D%9F"><span class="toc-number">1.10.</span> <span class="toc-text">10、列属性(列约束)</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#11%E3%80%81%E5%BB%BA%E8%A1%A8%E8%A7%84%E8%8C%83"><span class="toc-number">1.11.</span> <span class="toc-text">11、建表规范</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#12%E3%80%81SELECT"><span class="toc-number">1.12.</span> <span class="toc-text">12、SELECT</span></a></li></ol></li></ol></div></div></div></div></main><footer id="footer" style="background-image: url(/everyday/img/%E5%9B%BE%E7%89%875.jpg)"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2021 By 蔡哞哞</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div><div class="footer_custom_text">好好学习，<a  target="_blank" rel="noopener" href="https://butterfly.js.org/">天天向上</a>!</div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/everyday/js/utils.js"></script><script src="/everyday/js/main.js"></script><div class="js-pjax"><script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div><script defer="defer" id="fluttering_ribbon" mobile="true" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-fluttering-ribbon.min.js"></script><script id="click-heart" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/click-heart.min.js" async="async" mobile="false"></script></div></body></html>